package com.xiaoshuidi.cloud.module.contract.service.bill;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.mybatis.core.util.MyBatisUtils;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderInformationVo;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderFeesDetaillVo;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.orderFees.*;
import com.xiaoshuidi.cloud.module.contract.controller.app.bill.vo.OrderFeesDetailAppVo;
import com.xiaoshuidi.cloud.module.contract.convert.bill.OrderFeesConvert;
import com.xiaoshuidi.cloud.module.contract.convert.bill.RentOrderConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OrderFeesDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OrderFeesDetailDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.RentOrderDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.CustomerCompanyDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.OrderFeesMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.RentOrderMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.CustomerCompanyMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderFeeFlowTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderPayStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.PayMethodEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.CustomerTypeEnum;
import com.xiaoshuidi.cloud.module.contract.util.date.DateUtils;
import com.xiaoshuidi.cloud.module.contract.vo.OrderFeeAmountReqVO;
import com.xiaoshuidi.cloud.module.contract.vo.OrderFeeAmountRespVO;
import com.xiaoshuidi.cloud.module.contract.vo.OrderFeeDetailVO;
import lombok.extern.slf4j.Slf4j;
import com.xiaoshuidi.cloud.module.rooms.api.reserve.ReserveApi;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.CONTRACT_ORDERFEES_NOT_EXISTS;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.READJUST_AMOUNT_RESULT_DATA_ERROR;

/**
 * 账单明细 Service 实现类
 *
 * @author 合房租赁
 */
@Service
@Slf4j
public class OrderFeesServiceImpl implements OrderFeesService {

    @Resource
    private OrderFeesMapper orderfeesMapper;
    @Resource
    private RentOrderMapper rentOrderMapper;

    @Resource
    private CustomerCompanyMapper customerCompanyMapper;

    @Resource
    private ReserveApi reserveApi;

    /*
     * 创建账单明细
     * */
    @Override
    public Long createOrderFees(OrderFeesCreateReqVO createReqVO) {
        // 插入
        OrderFeesDO Orderfees = OrderFeesConvert.INSTANCE.convert(createReqVO);
        orderfeesMapper.insert(Orderfees);
        // 返回
        return Orderfees.getId();
    }

    /*
     * 批量创建账单明细
     * */
    @Override
    public List<OrderFeesDO> createBatchOrderFees(List<RentOrderDO> contractRentorder) {
        // 插入
        List<OrderFeesDO> contractOrderfees = new ArrayList<>();
        contractRentorder.forEach(item -> {
            item.getFeeDetail().forEach(fee -> {
                OrderFeesDO orderfeesDO = new OrderFeesDO();
                orderfeesDO.setOrderId(item.getId());
                orderfeesDO.setFeeSort(fee.getFeeSort());
                orderfeesDO.setFeeId(fee.getFeeId());
                orderfeesDO.setFeeName(fee.getFeeName());
                orderfeesDO.setAmount(fee.getAmount());
                orderfeesDO.setFeeMonth(fee.getFeeMonth());
                orderfeesDO.setStartTime(item.getStartTime());
                orderfeesDO.setEndTime(item.getEndTime());
                orderfeesDO.setDiscountAmount(fee.getDiscountAmount());
                orderfeesDO.setOrderType(fee.getOrderType());
                orderfeesDO.setFlowType(fee.getFlowType());
                orderfeesDO.setPaidAmount(fee.getPaidAmount());
                orderfeesDO.setMemberId(item.getMemberId());
                orderfeesDO.setOperatorName(item.getOperatorName());
                // 20230729 apartmentId与deptId一致
                orderfeesDO.setDeptId(item.getApartmentId());
                orderfeesDO.setBookingAmount(fee.getBookingAmount());
                if (Objects.nonNull(fee.getPayStatus())) {
                    orderfeesDO.setPayStatus(fee.getPayStatus());
                }
                contractOrderfees.add(orderfeesDO);
            });
        });

        log.info("======创建账单明细contractOrderfees：{}", contractOrderfees);
        orderfeesMapper.insertBatch(contractOrderfees);
        // 返回
        return contractOrderfees;
    }

    /*
     * 更新账单明细
     * */
    @Override
    public void updateContractOrderfees(OrderFeesUpdateReqVO updateReqVO) {
        // 校验存在
        validateOrderFeesExists(updateReqVO.getId());
        // 更新
        OrderFeesDO updateObj = OrderFeesConvert.INSTANCE.convert(updateReqVO);
        orderfeesMapper.updateById(updateObj);
    }

    /**
     * 批量修改账单明细
     * @param updateReqVOS
     */
    public void batchUpdate(List<OrderFeesDO> updateReqVOS){
        updateReqVOS.forEach(item->{
            // 校验存在
            OrderFeesDO orderFeesDO = orderfeesMapper.selectById(item.getId());
            if (orderFeesDO == null) {
                throw exception(CONTRACT_ORDERFEES_NOT_EXISTS);
            }
            BigDecimal readjustAmount = item.getReadjustAmount();
            if(readjustAmount.compareTo(new BigDecimal(0))<0){
                if(readjustAmount.abs().compareTo(orderFeesDO.getAmount())>=0)
                    throw exception(READJUST_AMOUNT_RESULT_DATA_ERROR);
            }
            // 更新
            orderfeesMapper.updateById(item);
        });
    }

    /*
     * 删除账单明细
     * */
    @Override
    public void deleteContractOrderfees(Long id) {
        // 校验存在
        validateOrderFeesExists(id);
        // 删除
        orderfeesMapper.deleteById(id);
    }

    private void validateOrderFeesExists(Long id) {
        if (orderfeesMapper.selectById(id) == null) {
            throw exception(CONTRACT_ORDERFEES_NOT_EXISTS);
        }
    }

    /*
     * 账单id 查询账单明细
     * */
    @Override
    public List<OrderFeesDetaillVo> getOrderDetail(Long orderId) {
        return orderfeesMapper.getOrderDetail(orderId);
    }

    /*
     *
     * 账单明细 账单总金额
     * */
    @Override
    public OrderFeesDetailVo getOrderFeeDetail(Long orderId) {
        List<OrderInformationVo> orderDetail = orderfeesMapper.getCostInformation(orderId);
//        BigDecimal totalReceivableAmount = orderDetail.stream()
//                .map(OrderFeesDetaillVo::getReceivableAmount)
//                // 使用reduce()聚合函数,实现累加器
//                .reduce(BigDecimal.ZERO,BigDecimal::add);
        // 应收总额
        BigDecimal totalReceivableAmount = BigDecimal.ZERO;
        // 待收总额
        BigDecimal totalNoPaidAmount = BigDecimal.ZERO;
        for (OrderInformationVo feesDetaillVo : orderDetail) {
            if (OrderFeeFlowTypeEnum.INFLOW.getCode().intValue() == feesDetaillVo.getFlowType()) {
                // 流入
                // 应收总额 费项应收金额累加
                totalReceivableAmount = totalReceivableAmount.add(feesDetaillVo.getReceivableAmount());
                // 待收总额 费项待付金额累加
                totalNoPaidAmount = totalNoPaidAmount.add(feesDetaillVo.getNoPaidAmount());
            } else if (OrderFeeFlowTypeEnum.OUTFLOW.getCode().intValue() == feesDetaillVo.getFlowType()) {
                totalReceivableAmount = totalReceivableAmount.subtract(feesDetaillVo.getReceivableAmount());
                totalNoPaidAmount = totalNoPaidAmount.subtract(feesDetaillVo.getNoPaidAmount());
            }
        }
        Integer totalReceivableFlowType = (totalReceivableAmount.compareTo(BigDecimal.ZERO) < 0) ?
                OrderFeeFlowTypeEnum.OUTFLOW.getCode() : OrderFeeFlowTypeEnum.INFLOW.getCode();
        totalReceivableAmount = (totalReceivableAmount.compareTo(BigDecimal.ZERO) < 0) ?
                totalReceivableAmount.multiply(new BigDecimal(-1)) : totalReceivableAmount;
        Integer totalNoPaidFlowType = (totalNoPaidAmount.compareTo(BigDecimal.ZERO) < 0) ?
                OrderFeeFlowTypeEnum.OUTFLOW.getCode() : OrderFeeFlowTypeEnum.INFLOW.getCode();
        totalNoPaidAmount = (totalNoPaidAmount.compareTo(BigDecimal.ZERO) < 0) ?
                totalNoPaidAmount.multiply(new BigDecimal(-1)) : totalNoPaidAmount;
        return OrderFeesDetailVo.builder()
                .totalReceivableAmount(totalReceivableAmount)
                .totalReceivableFlowType(totalReceivableFlowType)
                .totalNoPaidAmount(totalNoPaidAmount)
                .totalNoPaidFlowType(totalNoPaidFlowType)
                .orderFeesDetaillVos(orderDetail).build();
    }
    @Override
    public OrderInformationVo getOrderFeesById(Long id) {
        return orderfeesMapper.getOrderFeesById(id);
    }
    /*
     * 获取合同下的 账单明细
     * */
    @Override
    public List<OrderFeesDO> getOrderFeeListByContractId(Long contractId) {
        return orderfeesMapper.selectByContractId(contractId);
    }

    @Override
    public List<OrderFeesDO> getOrderFeeListByContractIds(List<Long> contractIds) {
        return orderfeesMapper.selectByContractIds(contractIds);
    }

    /**
     * 多个账单 账单明细
     */
    @Override
    public List<OrderFeesDO> getOrderFeeByorderIds(List<Long> orderIds, List<String> orderType) {
        LambdaQueryWrapper<OrderFeesDO> orderFeesDOQueryWrapper = new LambdaQueryWrapper<>();
        orderFeesDOQueryWrapper.in(OrderFeesDO::getOrderType, orderType)
                .in(OrderFeesDO::getFeeId, orderIds);
        //查询所有的明细账单
        List<OrderFeesDO> orderFeesDOS = orderfeesMapper.selectList(orderFeesDOQueryWrapper);
        return orderFeesDOS;
    }

    @Override
    public List<OrderFeesDO> getOrderFeesByOrderId(Long orderId) {
        if (Objects.isNull(orderId)) {
            return null;
        }
        LambdaQueryWrapper<OrderFeesDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderFeesDO::getOrderId, orderId);
        return orderfeesMapper.selectList(queryWrapper);
    }

    @Override
    public void updateOrderFeePaid(Long orderId, String payStatus) {
        orderfeesMapper.updatePayStatusByOrderId(orderId, payStatus);
    }

    @Override
    public PageResult<OrderDetailVo> getOrderFeesDetail(OrderFeesDetailReq req) {
        IPage<T> mpPage = MyBatisUtils.buildPage(req);

        IPage<OrderFeesDetailDO> orderFeesDetail = orderfeesMapper.getOrderFeesDetail(mpPage, req);

        PageResult<OrderDetailVo> result = new PageResult<>();
        result.setTotal(orderFeesDetail.getTotal());
        List<OrderFeesDetailDO> records = orderFeesDetail.getRecords();
        List<Long> collect = records.stream().map(OrderFeesDetailDO::getCustomerCompanyId).filter(Objects::nonNull).collect(Collectors.toList());
        Map<Long, CustomerCompanyDO> customerCompanyDOMap = null;
        if (CollectionUtils.isNotEmpty(collect)) {
            List<CustomerCompanyDO> customerCompanyDOS = customerCompanyMapper.selectBatchIds(collect);
            customerCompanyDOMap = customerCompanyDOS.stream().collect(Collectors.toMap(CustomerCompanyDO::getId, v -> v));
        }
        //设置承租人
        for (OrderFeesDetailDO record : records) {
            if (CustomerTypeEnum.COMPANY.getCode().equals(record.getCustomerType()) && customerCompanyDOMap != null) {
                CustomerCompanyDO customerCompanyDO = customerCompanyDOMap.get(record.getCustomerCompanyId());
                if (customerCompanyDO != null) {
                    record.setLesseeName(customerCompanyDO.getCompanyName());
                }
            } else {
                record.setLesseeName(record.getCustomerName());
            }
            if (record.getPayMethod() != null) {
                record.setTransactionSource(PayMethodEnum.getEnum(record.getPayMethod()).getMsg());
            } else {
                record.setTransactionSource(PayMethodEnum.PART.getMsg());
            }
        }
        result.setList(OrderFeesConvert.INSTANCE.convertDetail(records));
        return result;
    }

    @Override
    public List<OrderDetailExcelVo> exportContractExcel(OrderFeesDetailReq req) {
        List<OrderFeesDetailDO> orderFeesDetail = orderfeesMapper.getOrderFeesDetail(req);
        //设置承租人
        List<Long> collect = orderFeesDetail.stream().map(OrderFeesDetailDO::getCustomerCompanyId).filter(Objects::nonNull).collect(Collectors.toList());
        Map<Long, CustomerCompanyDO> customerCompanyDOMap = null;
        if (CollectionUtils.isNotEmpty(collect)) {
            List<CustomerCompanyDO> customerCompanyDOS = customerCompanyMapper.selectBatchIds(collect);
            customerCompanyDOMap = customerCompanyDOS.stream().collect(Collectors.toMap(CustomerCompanyDO::getId, v -> v));
        }
        for (OrderFeesDetailDO record : orderFeesDetail) {
            if (CustomerTypeEnum.COMPANY.getCode().equals(record.getCustomerType()) && customerCompanyDOMap != null) {
                CustomerCompanyDO customerCompanyDO = customerCompanyDOMap.get(record.getCustomerCompanyId());
                if (customerCompanyDO != null) {
                    record.setLesseeName(customerCompanyDO.getCompanyName());
                }
            } else {
                record.setLesseeName(record.getCustomerName());
            }
        }
        return OrderFeesConvert.INSTANCE.convertList01(orderFeesDetail);
    }

    /*
     *
     * 账单明细 账单总金额
     * */
    @Override
    public OrderFeesDetailAppVo getOrderFeeDetailApp(Long orderId) {
        List<OrderFeesDetaillVo> orderDetail = orderfeesMapper.getOrderDetail(orderId);
        if (CollectionUtils.isEmpty(orderDetail)) {
            return null;
        }
        BigDecimal totalReceivableAmount = orderDetail.stream()
                .map(OrderFeesDetaillVo::getReceivableAmount)
                // 使用reduce()聚合函数,实现累加器
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(orderId);
        if (rentOrderDO == null) {
            return null;
        }
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        String orderPeriod = rentOrderDO.getStartTime().format(dateFormat) + "~" + rentOrderDO.getEndTime().format(dateFormat);
        String oughtPayTime = rentOrderDO.getOughtPayTime().format(dateFormat);
        long daySpace = DateUtils.getDaySpace(rentOrderDO.getDeadlinePayTime(), LocalDate.now());
        String overdueDay = "";
        if (daySpace > 0) {
            overdueDay = "逾期" + daySpace + "天";
        }
        return OrderFeesDetailAppVo.builder().totalReceivableAmount(totalReceivableAmount)
                .orderFeesDetaillVos(orderDetail).overdueDay(overdueDay).orderPeriod(orderPeriod).oughtPayTime(oughtPayTime).
                roomName(rentOrderDO.getRoomName()).orderPeriod(orderPeriod).
                customerName(rentOrderDO.getCustomerName()).payer(rentOrderDO.getPayer()).remark(rentOrderDO.getRemark()).build();
    }

    @Override
    public void updateMemberUser(String mobile, String userName, String oldMobile, Long userId, Long oldUserId) {
        rentOrderMapper.updateMemberUser(mobile, userName, userId, oldUserId);
    }

    @Override
    public OrderFeeAmountRespVO getOrderAmountByFee(OrderFeeAmountReqVO req) {
        OrderFeeAmountRespVO orderAmountByFee = orderfeesMapper.getOrderAmountByFee(req);
        if (!ObjectUtils.isEmpty(orderAmountByFee)) {
            orderAmountByFee.setFeeId(req.getFeeId()).setSourceBizId(req.getSourceBizId().toString());
        }
        return orderAmountByFee;
    }

    @Override
    public List<OrderFeeDetailVO> getOrderDetailByOrderIds(List<Long> orderIds) {
        if (CollectionUtils.isEmpty(orderIds)){
            return null;
        }
        List<OrderFeesDO> orderFeesDOS = orderfeesMapper.selectList(OrderFeesDO::getOrderId, orderIds);
        if (CollectionUtils.isEmpty(orderFeesDOS)){
            return null;
        }
        return RentOrderConvert.INSTANCE.convert2(orderFeesDOS);
    }

    @Override
    public void updateOrderFeePaidAmount(Long id, String payStatus, BigDecimal paidAmount, LocalDateTime payTime) {
        if (OrderPayStatusEnum.PAID.getCode().equals(payStatus)){
            List<OrderFeesDO> orderFeesDOS = orderfeesMapper.selectList(OrderFeesDO::getOrderId, id);
            if (CollectionUtils.isEmpty(orderFeesDOS)){
                return;
            }
            BigDecimal totalAmount = orderFeesDOS.stream().map(f -> f.getAmount().subtract(f.getDiscountAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (totalAmount.compareTo(paidAmount) == 0){
                orderFeesDOS.stream().forEach(f -> {
                    f.setPayStatus(payStatus);
                    f.setActualPayTime(payTime);
                    f.setPaidAmount(f.getAmount().subtract(f.getDiscountAmount()));
                    f.setActualPaymentAmount(f.getPaidAmount());
                });
                orderfeesMapper.updateBatch(orderFeesDOS,orderFeesDOS.size());
            }else {
                LinkedList<OrderFeesDO> sortList = new LinkedList<>();
                for (OrderFeesDO orderFeesDO : orderFeesDOS) {
                    if (ApiConstants.DEPOSIT_FEE_ID.equals(orderFeesDO.getFeeId()) && ApiConstants.DEPOSIT.equals(orderFeesDO.getFeeSort())){
                        sortList.addLast(orderFeesDO);
                    }else {
                        sortList.addFirst(orderFeesDO);
                    }
                }
                for (OrderFeesDO orderFeesDO : sortList) {
                    orderFeesDO.setPayStatus(payStatus);
                    orderFeesDO.setActualPayTime(payTime);
                    orderFeesDO.setPaidAmount(orderFeesDO.getAmount().subtract(orderFeesDO.getDiscountAmount()));
                    if (paidAmount.compareTo(BigDecimal.ZERO) > 0){
                        paidAmount = paidAmount.subtract(orderFeesDO.getPaidAmount());
                        if (paidAmount.compareTo(BigDecimal.ZERO) >= 0){
                            orderFeesDO.setActualPaymentAmount(orderFeesDO.getPaidAmount());
                        }else {
                            // 剩余全部
                            orderFeesDO.setActualPaymentAmount(paidAmount.add(orderFeesDO.getPaidAmount()));
                        }
                    }else {
                        orderFeesDO.setActualPaymentAmount(BigDecimal.ZERO);
                    }
                }
                orderfeesMapper.updateBatch(sortList,sortList.size());
            }

        }else {
            orderfeesMapper.updatePayStatusByOrderId(id, payStatus);
        }
    }


    @Override
    public List<OrderFeesDO> getOrderFeeListByOrderId(Long orderId) {
        return orderfeesMapper.selectByOrderIdId(orderId);
    }

    @Override
    public void updateOrderFeeById(Long id) {
        orderfeesMapper.updateOrderFeeById(id);
    }

    @Override
    public void updateOrderFeeAmountById(Long id, BigDecimal paidAmount) {
        orderfeesMapper.updateOrderFeeAmountById(id, paidAmount);
    }
}
